package com.generator.service;

import com.generator.model.TableInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * CRUD代码生成器服务
 * 
 * @author Generator
 * @since 2024-01-01
 */
@Service
public class CrudGenerator {

    @Autowired
    private TemplateEngine templateEngine;

    private static final String DEFAULT_PACKAGE = "com.example";
    private static final String DEFAULT_AUTHOR = "Generator";
    private static final String OUTPUT_DIR = "./generated-code";

    /**
     * 生成CRUD代码
     * 
     * @param tableInfo 表信息
     * @param packageName 包名
     * @param author 作者
     * @return 生成的代码文件路径映射
     */
    public Map<String, String> generateCrudCode(TableInfo tableInfo, String packageName, String author) {
        return generateCrudCode(tableInfo, packageName, author, OUTPUT_DIR);
    }

    /**
     * 生成CRUD代码
     * 
     * @param tableInfo 表信息
     * @param packageName 包名
     * @param author 作者
     * @param outputDir 输出目录
     * @return 生成的代码文件路径映射
     */
    public Map<String, String> generateCrudCode(TableInfo tableInfo, String packageName, String author, String outputDir) {
        Map<String, String> generatedFiles = new HashMap<>();
        
        // 设置基本信息
        if (packageName == null || packageName.trim().isEmpty()) {
            packageName = DEFAULT_PACKAGE;
        }
        if (author == null || author.trim().isEmpty()) {
            author = DEFAULT_AUTHOR;
        }
        
        tableInfo.setPackageName(packageName);
        tableInfo.setAuthor(author);

        try {
            // 创建输出目录
            createOutputDirectories(packageName, tableInfo.getEntityName(), outputDir);
            
            // 生成实体类
            String entityCode = generateEntity(tableInfo);
            generatedFiles.put("Entity", entityCode);
            writeToFile(entityCode, getEntityPath(packageName, tableInfo.getEntityName(), outputDir));

            // 生成Mapper接口
            String mapperCode = generateMapper(tableInfo);
            generatedFiles.put("Mapper", mapperCode);
            writeToFile(mapperCode, getMapperPath(packageName, tableInfo.getEntityName(), outputDir));

            // 生成Service接口
            String serviceCode = generateService(tableInfo);
            generatedFiles.put("Service", serviceCode);
            writeToFile(serviceCode, getServicePath(packageName, tableInfo.getEntityName(), outputDir));

            // 生成Service实现类
            String serviceImplCode = generateServiceImpl(tableInfo);
            generatedFiles.put("ServiceImpl", serviceImplCode);
            writeToFile(serviceImplCode, getServiceImplPath(packageName, tableInfo.getEntityName(), outputDir));

            // 生成Controller
            String controllerCode = generateController(tableInfo);
            generatedFiles.put("Controller", controllerCode);
            writeToFile(controllerCode, getControllerPath(packageName, tableInfo.getEntityName(), outputDir));

        } catch (Exception e) {
            throw new RuntimeException("生成代码失败: " + e.getMessage(), e);
        }

        return generatedFiles;
    }

    /**
     * 生成实体类代码
     */
    private String generateEntity(TableInfo tableInfo) {
        Context context = createContext(tableInfo);
        return templateEngine.process("code/entity", context);
    }

    /**
     * 生成Mapper接口代码
     */
    private String generateMapper(TableInfo tableInfo) {
        Context context = createContext(tableInfo);
        return templateEngine.process("code/mapper", context);
    }

    /**
     * 生成Service接口代码
     */
    private String generateService(TableInfo tableInfo) {
        Context context = createContext(tableInfo);
        return templateEngine.process("code/service", context);
    }

    /**
     * 生成Service实现类代码
     */
    private String generateServiceImpl(TableInfo tableInfo) {
        Context context = createContext(tableInfo);
        return templateEngine.process("code/serviceImpl", context);
    }

    /**
     * 生成Controller代码
     */
    private String generateController(TableInfo tableInfo) {
        Context context = createContext(tableInfo);
        return templateEngine.process("code/controller", context);
    }

    /**
     * 创建模板上下文
     */
    private Context createContext(TableInfo tableInfo) {
        Context context = new Context();
        context.setVariable("table", tableInfo);
        context.setVariable("package", tableInfo.getPackageName());
        context.setVariable("author", tableInfo.getAuthor());
        context.setVariable("date", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        context.setVariable("datetime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return context;
    }

    /**
     * 创建输出目录
     */
    private void createOutputDirectories(String packageName, String entityName) {
        createOutputDirectories(packageName, entityName, OUTPUT_DIR);
    }

    /**
     * 创建输出目录
     */
    private void createOutputDirectories(String packageName, String entityName, String outputDir) {
        String baseDir = outputDir + "/" + packageName.replace(".", "/");
        
        new File(baseDir + "/entity").mkdirs();
        new File(baseDir + "/mapper").mkdirs();
        new File(baseDir + "/service").mkdirs();
        new File(baseDir + "/service/impl").mkdirs();
        new File(baseDir + "/controller").mkdirs();
    }

    /**
     * 写入文件
     */
    private void writeToFile(String content, String filePath) throws IOException {
        File file = new File(filePath);
        file.getParentFile().mkdirs();
        
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(content);
        }
    }

    // 获取各种文件路径的方法
    private String getEntityPath(String packageName, String entityName) {
        return getEntityPath(packageName, entityName, OUTPUT_DIR);
    }

    private String getEntityPath(String packageName, String entityName, String outputDir) {
        return outputDir + "/" + packageName.replace(".", "/") + "/entity/" + entityName + ".java";
    }

    private String getMapperPath(String packageName, String entityName) {
        return getMapperPath(packageName, entityName, OUTPUT_DIR);
    }

    private String getMapperPath(String packageName, String entityName, String outputDir) {
        return outputDir + "/" + packageName.replace(".", "/") + "/mapper/" + entityName + "Mapper.java";
    }

    private String getServicePath(String packageName, String entityName) {
        return getServicePath(packageName, entityName, OUTPUT_DIR);
    }

    private String getServicePath(String packageName, String entityName, String outputDir) {
        return outputDir + "/" + packageName.replace(".", "/") + "/service/" + entityName + "Service.java";
    }

    private String getServiceImplPath(String packageName, String entityName) {
        return getServiceImplPath(packageName, entityName, OUTPUT_DIR);
    }

    private String getServiceImplPath(String packageName, String entityName, String outputDir) {
        return outputDir + "/" + packageName.replace(".", "/") + "/service/impl/" + entityName + "ServiceImpl.java";
    }

    private String getControllerPath(String packageName, String entityName) {
        return getControllerPath(packageName, entityName, OUTPUT_DIR);
    }

    private String getControllerPath(String packageName, String entityName, String outputDir) {
        return outputDir + "/" + packageName.replace(".", "/") + "/controller/" + entityName + "Controller.java";
    }
}